<?php
namespace App\Services\Activity;

use App\Exceptions\BasicException;
use App\Models\ActivityDB\ActivityRewardLog;
use App\Models\ActivityDB\ActivityTaskSetting;
use App\Models\ActivityDB\ActivityTaskTemplate;
use App\Models\MainDB\AccountLog;
use App\Models\MainDB\Coin;
use App\Models\MainDB\Gift;
use App\Models\MainDB\GiftBackpack;
use App\Models\MainDB\MallOrders;
use App\Models\MainDB\MallProducts;
use App\Models\MainDB\User;
use App\Models\MainDB\UserData;
use App\Models\MainDB\UserRecharge;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis;

class TaskRecordService
{

    public function springBeforeReceive(int $userId, int $taskId)
    {
        $activityTaskSettingModel = new ActivityTaskSetting();
        $activityInfo = $activityTaskSettingModel->getValidByType($activityTaskSettingModel::TYPE_SPRING);
        if (empty($activityInfo)) {
            throw new BasicException(50001);
        }

        $templateInfo = ActivityTaskTemplate::query()->find($taskId, ['coin']);
        if (empty($templateInfo)) {
            throw new BasicException(50003);
        }
        $totalRechargeCoin = (new UserRecharge)->getUserTotalRechargeCoin($userId, strtotime($activityInfo->end_at), strtotime($activityInfo->start_at));
        if (bccomp($totalRechargeCoin, $templateInfo->coin, 2) === -1) {
            throw new BasicException(50004);
        }

        if (empty($taskId)) {
            throw new BasicException(50006);
        }

        return [
            'task_id'         => $taskId,
            'task_setting_id' => $activityInfo->id,
        ];
    }

    public function comeHomeBeforeReceive(int $userId)
    {
        $activityTaskSettingModel = new ActivityTaskSetting();
        $activityInfo = $activityTaskSettingModel->getValidByType($activityTaskSettingModel::TYPE_COME_HOME);
        if (empty($activityInfo)) {
            throw new BasicException(50001);
        }
        $type = $activityInfo->type;

        $totalRechargeCoin = (new UserRecharge)->getUserTotalRechargeCoin($userId, strtotime($activityInfo->end_recharge_at));
        $taskId = ActivityTaskTemplate::query()
            ->where('type', $type)
            ->where('coin', '<=', $totalRechargeCoin)
            ->orderByDesc('coin')
            ->value('id');

        if (empty($taskId)) {
            throw new BasicException(50006);
        }

        return [
            'task_id'         => $taskId,
            'task_setting_id' => $activityInfo->id,
        ];
    }

    public function goddessBeforeReceive(int $userId)
    {
        $activityTaskSettingModel = new ActivityTaskSetting();
        $activityInfo = $activityTaskSettingModel->getValidByType($activityTaskSettingModel::TYPE_GODDESS);
        if (empty($activityInfo)) {
            throw new BasicException(50001);
        }
        $type = $activityInfo->type;
        $userData = UserData::query()->where('user_id', $userId)->select('sex')->first();
        if ($userData->sex != 2) {
            throw new BasicException(50002);
        }
        $taskId = ActivityTaskTemplate::query()->where('type', $type)->value('id');

        if (empty($taskId)) {
            throw new BasicException(50006);
        }

        return [
            'task_id'         => $taskId,
            'task_setting_id' => $activityInfo->id,
        ];
    }

    public function receive(int $taskId, int $userId, int $taskSettingId)
    {
        try {

            $lockKey = sprintf('38activity_receive_locked_%s_%s', $userId, $taskId);
            if (! Redis::SET($lockKey, 'locked', 'nx', 'ex', 10)) {
                throw new BasicException(50007);
            }

            $rewardLog = [];
            $activityRewardLogModel = new ActivityRewardLog();

            $db = DB::connection('mysql');
            $activityDb = DB::connection($activityRewardLogModel->getConnectionName());
            $db->beginTransaction();
            $activityDb->beginTransaction();

            $rewardLogInfo = ActivityRewardLog::query()
                                ->where('user_id', $userId)
                                ->where('task_id', $taskId)
                                ->lockForUpdate()
                                ->pluck('id');

            if ($rewardLogInfo->isNotEmpty()) {
                throw new BasicException(50005);
            }

            $rewards = (new TaskRewardService)->normal($taskId);

            if ($rewards->isNotEmpty()) {

                // 礼物
                $rewards->where('reward_type', Gift::RELATION_TYPE)->each(function ($item) use ($userId, &$rewardLog, $taskId, $taskSettingId) {
                    if (! empty($item->reward)) {
                        (new GiftBackpack())->addGift($userId, $item->reward->id, $item->count);
                        $rewardLog[] = $this->makeRewardLogData($item, $userId, $taskId, $taskSettingId);
                    }
                });

                // 商品
                $rewards->where('reward_type', MallProducts::RELATION_TYPE)->each(function ($item) use ($userId, &$rewardLog, $taskId, $taskSettingId) {
                    if (! empty($item->reward)) {
                        (new MallOrders())->addProduct($userId, $item->reward->id, $item->count, $item->reward->category_id);
                        $rewardLog[] = $this->makeRewardLogData($item, $userId, $taskId, $taskSettingId);
                    }
                });

                // 金币
                $totalCoin = $rewards->where('reward_type', Coin::RELATION_TYPE)->each(function ($item) use ($userId, &$rewardLog, $taskId, $taskSettingId) {

                    $item->total_coin = 0;
                    $rewardLogInfo = $this->makeRewardLogData($item, $userId, $taskId, $taskSettingId);

                    if (! empty($rewardLogInfo['total_coin'])) {
                        $item->total_coin = $rewardLogInfo['total_coin'];
                        $rewardLog[] = $rewardLogInfo;
                    }

                })->sum('total_coin');

                if ($rewardLog) {
                    ActivityRewardLog::query()->insert($rewardLog);
                }

                if ($totalCoin) {
                    User::query()->where('user_id', $userId)->increment('money', $totalCoin);
                    app('model_account_log')->addLog($userId, $totalCoin, "活动金币", 226);
                }


            }

            $db->commit();
            $activityDb->commit();

        } catch (\Throwable $exception) {
            isset($db) && $db->rollBack();
            isset($activityDb) && $activityDb->rollBack();
            throw new \PDOException($exception->getMessage());
        }
        return $rewards;

    }

    public function taskDesc()
    {
        return '活动任务奖励';
    }

    private function makeRewardLogData($item, int $userId, int $taskId, int $taskSettingId)
    {
        $totalCoin = MallProducts::RELATION_TYPE == $item->reward_type ? 0 : $item->count * $item->reward->price;
        $row = [
            'task_id'         => $taskId,
            'task_setting_id' => $taskSettingId,
            'user_id'         => $userId,
            'reward_type'     => $item->reward_type,
            'reward_id'       => $item->reward_id,
            'count'           => $item->count,
            'total_coin'      => $totalCoin,
            'desc'            => $this->taskDesc()
        ];
        return $row;
    }


}
